package com.dxj.security.filter;
import com.dxj.security.domain.LoginUser;
import com.dxj.utils.JwtUtil;
import com.dxj.utils.RedisCache;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author dxj
 * @Description jwt 认证过滤器  从 JWT 中提取用户信息并将其设置为当前的安全上下文
 * OncePerRequestFilter 确保每个请求在过滤器链中只通过一次
 * @date 2024/7/28 18:12
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Resource
    private JwtUtil tokenService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        //请求中提取 JWT 并解析出用户信息
        LoginUser loginUser = tokenService.getLoginUser(request);
        //对象是否不为空，并且当前的安全上下文还没有认证信息,尚未通过身份验证
        if (loginUser!=null&& SecurityContextHolder.getContext().getAuthentication()==null)
        {
            //验证令牌有效期
            tokenService.verifyToken(loginUser);
            //提取权限
            List<SimpleGrantedAuthority> userRoles=loginUser.getRoles()
                    .stream()
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList());
            //LoginUser对象作为用户名，null 作为密码（因为不需要）以及从 LoginUser 对象中获取的权限集作为权限
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, userRoles);
            //setDetails 方法将请求的详细信息（如 IP 地址、会话 ID 等）设置到 UsernamePasswordAuthenticationToken 对象中。
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            //将创建的 UsernamePasswordAuthenticationToken 对象设置到当前的安全上下文中,Spring Security 的其他部分就可以基于这个认证信息进行后续的安全检查了。
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}
